﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using BitMiracle.LibTiff.Classic;

namespace TiffWriteRead
{
    /// <summary>
    /// 自定义TIFF标签定义
    /// </summary>
    public static class CustomTiffTags
    {
        public const TiffTag PSIA_TIFFTAG_MagicNumber = (TiffTag)50432;
        public const TiffTag PSIA_TIFFTAG_Version = (TiffTag)50433;
        public const TiffTag PSIA_TIFFTAG_Data = (TiffTag)50434;
        public const TiffTag PSIA_TIFFTAG_Header = (TiffTag)50435;
        public const TiffTag PSIA_TIFFTAG_Comments = (TiffTag)50436;
        public const TiffTag PSIA_TIFFTAG_XML = (TiffTag)50441;
        public const TiffTag CUSTOM_TIFF_DATA = (TiffTag)55555;
    }

    /// <summary>
    /// TIFF文件头结构
    /// </summary>
    [System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential, Pack = 1)]
    public struct TIFFHeader
    {
        [System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst = 2)]
        public byte[] ByteOrder; // "MM"或"II"
        public ushort Version;    // 版本号42
        public uint FirstIFDOffset; // 第一个IFD的偏移量
    }

    /// <summary>
    /// IFD条目结构
    /// </summary>
    [System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential, Pack = 1)]
    public struct IFDEntry
    {
        public ushort Tag;          // 标签ID
        public ushort Type;         // 数据类型
        public uint Count;          // 数据个数
        public uint ValueOffset;    // 数据值或者偏移
    }

    /// <summary>
    /// PSIA头部结构
    /// </summary>
    [System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential, Pack = 1)]
    public struct PSIAHeader
    {
        public uint ImageType;
        [System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst = 64)]
        public byte[] SourceName;
        [System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst = 16)]
        public byte[] ImageMode;
        public double LpfStrength;
        public uint AutoFlatten;
        public uint AcTrack;
        public uint Xres;
        public uint Yres;
        public double Angle;
        public uint SineScan;
        public double OverscanRate;
        public uint Forward;
        public uint ScanUp;
        public uint SwapXY;
        public double XReal;
        public double YReal;
        public double XOffset;
        public double YOffset;
        public double ScanRate;
        public double SetPoint;
        [System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst = 16)]
        public byte[] SetPointUnit;
        public double TipBias;
        public double SampleBias;
        public double DataGain;
        public double ZScale;
        public double ZOffset;
        [System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst = 16)]
        public byte[] ZUnit;
        public uint DataMin;
        public uint DataMax;
        public uint DataAvg;
        public uint Compression;
        public uint Logscale;
        public uint Square;
        public double ZServoGain;
        public double ZScannerRange;
        [System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst = 16)]
        public byte[] XYVoltageMode;
        [System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst = 16)]
        public byte[] ZVoltageMode;
        [System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst = 16)]
        public byte[] XYServoMode;
        public uint DataType;
        public uint Reserved1;
        public uint Reserved2;
        public double NcmAmplitude;
        public double NcmFrequency;
        public double HeadRotateAngle;
        [System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst = 32)]
        public byte[] CantileverName;
        [System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst = 164)]
        public byte[] Tail;
    }

    // Tiff自定义数据类型
    [System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential, Pack = 1)]
    public struct TiffCustomData
    {
        public float ROI_x1;
        public float ROI_y1;
        public float ROI_x2;
        public float ROI_y2;
    }

    // TIFF信息类
    public class TIFFINFO
    {
        /// <summary>
        /// 用于界面显示图像数据字节数
        /// </summary>
        public List<byte> ShowPoints { get; set; }

        /// <summary>
        /// 原始数据点数
        /// </summary>
        public List<double> OriginPoints { get; set; }

        /// <summary>
        /// 显示分辨率-宽度
        /// </summary>
        public int XShowRes { get; set; }

        /// <summary>
        /// 显示分辨率-高度
        /// </summary>
        public int YShowRes { get; set; }

        /// <summary>
        /// Points
        /// </summary>
        public int XOriginRes { get; set; }

        /// <summary>
        /// Lines
        /// </summary>
        public int YOriginRes { get; set; }

        /// <summary>
        /// 实际宽度
        /// </summary>
        public double XReal { get; set; }

        /// <summary>
        /// 实际高度
        /// </summary>
        public double YReal { get; set; }

        /// <summary>
        /// 实际尺寸单位
        /// </summary>
        public string XyUnit { get; set; }

        public string ZUnit { get; set; }

        /// <summary>
        /// 角度
        /// </summary>
        public double Angle { get; set; }

        #region 自定义数据

        public float ROI_x1 { get; set; }
        public float ROI_y1 { get; set; }
        public float ROI_x2 { get; set; }
        public float ROI_y2 { get; set; }

        #endregion

        public TIFFINFO()
        {
            ShowPoints = new List<byte>();
            OriginPoints = new List<double>();
            XShowRes = 0;
            YShowRes = 0;
            XOriginRes = 0;
            YOriginRes = 0;
            XReal = 0;
            YReal = 0;
            Angle = 0;
            XyUnit = "um";
            ZUnit = "um";
            ROI_x1 = 0;
            ROI_y1 = 0;
            ROI_x2 = 0;
            ROI_y2 = 0;
        }
    }

    public static class TiffHelper
    {
        #region Read Tiff  

        /// <summary>
        /// 读取TIFF数据
        /// </summary>
        /// <param name="filePath"></param>
        /// <param name="info"></param>
        /// <returns></returns>
        public static bool ReadDataFromTiff(string filePath, TIFFINFO info)
        {
            Console.WriteLine($"输入文件路径：{filePath}");

            if (!File.Exists(filePath))
            {
                Console.WriteLine($"无法打开文件,路径为{filePath}");
                return false;
            }

            try
            {
                using (FileStream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read))
                using (BinaryReader reader = new BinaryReader(fileStream))
                {
                    // 读取TIFF头
                    TIFFHeader tiffHeader = new TIFFHeader
                    {
                        ByteOrder = reader.ReadBytes(2),
                        Version = reader.ReadUInt16(),
                        FirstIFDOffset = reader.ReadUInt32()
                    };

                    // 跳转到第一个IFD
                    fileStream.Seek(tiffHeader.FirstIFDOffset, SeekOrigin.Begin);
                    ushort numEntries = reader.ReadUInt16();

                    PSIAHeader header = new PSIAHeader();
                    uint stripOffset = 0;
                    uint stripByteCounts = 0;
                    List<byte> imgData = new List<byte>();
                    List<double> originImageData = new List<double>();
                    TiffCustomData customData = new TiffCustomData();
                    ushort imageWidth = 0;
                    ushort imageHeight = 0;

                    // 遍历所有IFD条目
                    for (int i = 0; i < numEntries; i++)
                    {
                        IFDEntry entry = new IFDEntry
                        {
                            Tag = reader.ReadUInt16(),
                            Type = reader.ReadUInt16(),
                            Count = reader.ReadUInt32(),
                            ValueOffset = reader.ReadUInt32()
                        };

                        long currentPos = fileStream.Position;

                        switch ((int)entry.Tag)
                        {
                            case 50435: // PSIA_TIFFTAG_Header
                                fileStream.Seek(entry.ValueOffset, SeekOrigin.Begin);
                                byte[] headerBytes = reader.ReadBytes((int)entry.Count);
                                header = ByteArrayToStructure<PSIAHeader>(headerBytes);
                                Console.WriteLine("read head info success!");
                                PSIAHeaderToTiffInfo(header, info);
                                fileStream.Seek(currentPos, SeekOrigin.Begin);
                                break;

                            case 50434: // PSIA_TIFFTAG_Data
                                fileStream.Seek(entry.ValueOffset, SeekOrigin.Begin);
                                imgData = new List<byte>(reader.ReadBytes((int)entry.Count));

                                originImageData = new List<double>(imgData.Count / 4);
                                for (int j = 0; j < imgData.Count / 4; j++)
                                {
                                    float value = BitConverter.ToSingle(imgData.ToArray(), j * 4);
                                    originImageData.Add(value);
                                }

                                info.OriginPoints = new List<double>(originImageData);
                                Console.WriteLine("read PSIA TIFF Data success");
                                fileStream.Seek(currentPos, SeekOrigin.Begin);
                                break;

                            case 256: // TIFFTAG_IMAGEWIDTH
                                imageWidth = (ushort)entry.ValueOffset;
                                info.XShowRes = imageWidth;
                                break;

                            case 257: // TIFFTAG_IMAGELENGTH
                                imageHeight = (ushort)entry.ValueOffset;
                                info.YShowRes = imageHeight;
                                break;

                            case 273: // TIFFTAG_STRIPOFFSETS
                                stripOffset = entry.ValueOffset;
                                break;

                            case 279: // TIFFTAG_STRIPBYTECOUNTS
                                stripByteCounts = entry.ValueOffset;
                                break;

                            case 55555: // CUSTOM_TIFF_DATA
                                fileStream.Seek(entry.ValueOffset, SeekOrigin.Begin);
                                byte[] customDataBytes = reader.ReadBytes((int)entry.Count);
                                customData = ByteArrayToStructure<TiffCustomData>(customDataBytes);
                                CustomDataToTiffInfo(customData, info);
                                fileStream.Seek(currentPos, SeekOrigin.Begin);
                                break;
                        }
                    }

                    // 读取显示数据
                    fileStream.Seek(stripOffset, SeekOrigin.Begin);
                    byte[] rawData = reader.ReadBytes((int)stripByteCounts);
                    info.ShowPoints = new List<byte>(rawData);

                    // 客户的数据需要乘上data_gain
                    for (int i = 0; i < info.OriginPoints.Count; i++)
                    {
                        info.OriginPoints[i] *= header.DataGain;
                    }
                }

                return true;
            }
            catch (Exception ex)
            {
                throw new Exception($"读取TIFF文件时出错: {ex.Message}");
            }
        }

        /// <summary>
        /// 从uint8数组生成字符串(特殊格式，每个字母中间使用0填充)
        /// </summary>
        /// <param name="uint8Array"></param>
        /// <returns></returns>
        private static string GenerateStringFromUint8(byte[] uint8Array)
        {
            StringBuilder sb = new StringBuilder();
            int length = 0;

            while (length < uint8Array.Length && uint8Array[2 * length] != 0)
            {
                length++;
            }

            for (int i = 0; i < length; i++)
            {
                sb.Append((char)uint8Array[2 * i]);
            }

            return sb.ToString();
        }

        /// <summary>
        /// PSIA头部信息转TIFF信息
        /// </summary>
        /// <param name="header"></param>
        /// <param name="info"></param>
        /// <returns></returns>
        private static bool PSIAHeaderToTiffInfo(PSIAHeader header, TIFFINFO info)
        {
            info.XOriginRes = (int)header.Xres;
            info.YOriginRes = (int)header.Yres;
            info.XReal = header.XReal;
            info.YReal = header.YReal;
            info.XyUnit = GenerateStringFromUint8(header.SetPointUnit);
            info.ZUnit = GenerateStringFromUint8(header.ZUnit);
            info.Angle = header.Angle;
            return true;
        }

        /// <summary>
        /// CustomData信息转TIFF信息
        /// </summary>
        /// <param name="customData"></param>
        /// <param name="info"></param>
        /// <returns></returns>
        private static bool CustomDataToTiffInfo(TiffCustomData customData, TIFFINFO info)
        {
            info.ROI_x1 = customData.ROI_x1;
            info.ROI_y1 = customData.ROI_y1;
            info.ROI_x2 = customData.ROI_x2;
            info.ROI_y2 = customData.ROI_y2;
            return true;
        }

        /// <summary>
        /// 字节数组转结构体
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="bytes"></param>
        /// <returns></returns>
        /// <exception cref="ArgumentException"></exception>
        private static T ByteArrayToStructure<T>(byte[] bytes) where T : struct
        {
            int size = System.Runtime.InteropServices.Marshal.SizeOf(typeof(T));
            if (bytes.Length < size)
            {
                throw new ArgumentException("字节数组长度不足");
            }

            IntPtr ptr = System.Runtime.InteropServices.Marshal.AllocHGlobal(size);
            try
            {
                System.Runtime.InteropServices.Marshal.Copy(bytes, 0, ptr, size);
                return (T)System.Runtime.InteropServices.Marshal.PtrToStructure(ptr, typeof(T));
            }
            finally
            {
                System.Runtime.InteropServices.Marshal.FreeHGlobal(ptr);
            }
        }

        #endregion

        #region Write Tiff

        /// <summary>
        /// 写入TIFF数据
        /// </summary>
        /// <param name="outputPath"></param>
        /// <param name="info"></param>
        /// <returns></returns>
        public static bool WriteDataToTiff(string outputPath, TIFFINFO info)
        {
            try
            {
                // 创建并填充PSIA头部
                PSIAHeader header = CreateDefaultPSIAHeader();
                if (!TiffInfoToPSIAHeader(info, ref header))
                {
                    Console.WriteLine("无法转换信息");
                    return false;
                }

                // 创建自定义数据
                TiffCustomData customData = new TiffCustomData();
                TiffInfoToCustomData(info, ref customData);

                // 准备原始图像数据
                int dataLength = 4 * (int)header.Xres * (int)header.Yres;
                byte[] dataImg = new byte[dataLength];

                for (int i = 0; i < header.Xres * header.Yres; i++)
                {
                    byte[] floatBytes = BitConverter.GetBytes(info.OriginPoints[i]);
                    Array.Copy(floatBytes, 0, dataImg, i * 4, 4);
                }

                // 准备头部数据
                byte[] dataHead = StructureToByteArray(header);
                if (dataHead.Length > 580)
                {
                    Array.Resize(ref dataHead, 580);
                }
                else if (dataHead.Length < 580)
                {
                    byte[] temp = new byte[580];
                    Array.Copy(dataHead, temp, dataHead.Length);
                    dataHead = temp;
                }

                // 准备自定义数据
                byte[] customDataBytes = StructureToByteArray(customData);

                // XML数据
                string xmlData = "<?xml version=\"1.0\" encoding=\"UTF - 8\"?> <ExtendHeader> <Version>256</Version> <SampleName>Wafer</SampleName> <UseDieInfo>TRUE</UseDieInfo> <DieIndexX>0</DieIndexX> <DieIndexY>0</DieIndexY> <DieCoordX>20917.47476313945</DieCoordX> <DieCoordY>20535.096705205106</DieCoordY> <DieMapInfo><SampleDiameter>300.0</SampleDiameter> <DieOnEdge>TRUE</DieOnEdge> <EdgeSize>0.0</EdgeSize> <DieSizeX>25.92309</DieSizeX> <DieSizeY>32.79632</DieSizeY> <DieOffsetX>-12.37371</DieOffsetX> <DieOffsetY>-16.4352</DieOffsetY> <DieAddressConfigure>TRUE</DieAddressConfigure> <CenterDieX>0</CenterDieX> <CenterDieY>0</CenterDieY> <XReverse>FALSE</XReverse> <YReverse>FALSE</YReverse> </DieMapInfo></ExtendHeader>";

                // 使用LibTiff写入标准TIFF
                using (Tiff tif = Tiff.Open(outputPath, "w"))
                {
                    if (tif == null)
                    {
                        Console.WriteLine($"无法创建TIFF文件: {outputPath}");
                        return false;
                    }

                    // 设置标准标签
                    tif.SetField(TiffTag.IMAGEWIDTH, info.XShowRes);
                    tif.SetField(TiffTag.IMAGELENGTH, info.YShowRes);
                    tif.SetField(TiffTag.BITSPERSAMPLE, 8);
                    tif.SetField(TiffTag.COMPRESSION, Compression.NONE);
                    tif.SetField(TiffTag.PHOTOMETRIC, Photometric.RGB);
                    tif.SetField(TiffTag.SAMPLESPERPIXEL, 3);
                    tif.SetField(TiffTag.PLANARCONFIG, PlanarConfig.CONTIG);
                    tif.SetField(TiffTag.RESOLUTIONUNIT, ResUnit.INCH);

                    // 写入显示数据
                    byte[] rgbData = info.ShowPoints.ToArray();
                    for (int row = 0; row < info.YShowRes; row++)
                    {
                        tif.WriteScanline(rgbData, row * info.XShowRes * 3, row, 0);
                    }

                    tif.Close();
                }

                // 手动添加自定义标签到文件
                using (FileStream fileStream = new FileStream(outputPath, FileMode.Open, FileAccess.ReadWrite))
                using (BinaryWriter writer = new BinaryWriter(fileStream))
                using (BinaryReader reader = new BinaryReader(fileStream))
                {
                    // 读取TIFF头
                    fileStream.Seek(0, SeekOrigin.Begin);
                    byte[] byteOrder = reader.ReadBytes(2);
                    bool isBigEndian = (byteOrder[0] == 'M' && byteOrder[1] == 'M');
                    ushort version = reader.ReadUInt16();
                    uint firstIFDOffset = reader.ReadUInt32();

                    // 在文件末尾写入原始图像数据
                    fileStream.Seek(0, SeekOrigin.End);
                    long imageDataOffset = fileStream.Position;
                    writer.Write(dataImg);

                    // 读取IFD
                    fileStream.Seek(firstIFDOffset, SeekOrigin.Begin);
                    ushort numEntries = reader.ReadUInt16();
                    long ifdEntriesStart = fileStream.Position;

                    // 读取所有现有IFD条目
                    List<IFDEntry> entries = new List<IFDEntry>();
                    for (int i = 0; i < numEntries; i++)
                    {
                        IFDEntry entry = new IFDEntry
                        {
                            Tag = reader.ReadUInt16(),
                            Type = reader.ReadUInt16(),
                            Count = reader.ReadUInt32(),
                            ValueOffset = reader.ReadUInt32()
                        };
                        entries.Add(entry);
                    }

                    uint nextIFDOffset = reader.ReadUInt32();

                    // 准备写入自定义标签数据到文件末尾
                    fileStream.Seek(0, SeekOrigin.End);
                    long customDataStart = fileStream.Position;

                    // 写入各个自定义数据
                    long headerOffset = fileStream.Position;
                    writer.Write(dataHead);

                    long xmlOffset = fileStream.Position;
                    byte[] xmlBytes = Encoding.ASCII.GetBytes(xmlData);
                    writer.Write(xmlBytes);

                    long aimiCustomOffset = fileStream.Position;
                    writer.Write(customDataBytes);

                    // 创建新的IFD条目（添加自定义标签）
                    List<IFDEntry> newEntries = new List<IFDEntry>(entries);

                    newEntries.Add(new IFDEntry { Tag = 50432, Type = 4, Count = 1, ValueOffset = 235082497 }); // PSIA_TIFFTAG_MagicNumber
                    newEntries.Add(new IFDEntry { Tag = 50433, Type = 4, Count = 1, ValueOffset = 16777218 }); // PSIA_TIFFTAG_Version
                    newEntries.Add(new IFDEntry { Tag = 50434, Type = 1, Count = (uint)dataLength, ValueOffset = (uint)imageDataOffset }); // PSIA_TIFFTAG_Data
                    newEntries.Add(new IFDEntry { Tag = 50435, Type = 7, Count = 580, ValueOffset = (uint)headerOffset }); // PSIA_TIFFTAG_Header
                    newEntries.Add(new IFDEntry { Tag = 50441, Type = 2, Count = (uint)xmlBytes.Length, ValueOffset = (uint)xmlOffset }); // PSIA_TIFFTAG_XML
                    newEntries.Add(new IFDEntry { Tag = 55555, Type = 7, Count = (uint)customDataBytes.Length, ValueOffset = (uint)aimiCustomOffset }); // CUSTOM_TIFF_DATA

                    // 按tag排序
                    newEntries.Sort((a, b) => a.Tag.CompareTo(b.Tag));

                    // 重写IFD
                    fileStream.Seek(firstIFDOffset, SeekOrigin.Begin);
                    writer.Write((ushort)newEntries.Count);

                    foreach (var entry in newEntries)
                    {
                        writer.Write(entry.Tag);
                        writer.Write(entry.Type);
                        writer.Write(entry.Count);
                        writer.Write(entry.ValueOffset);
                    }

                    writer.Write(nextIFDOffset);
                }

                Console.WriteLine("保存PSIA格式TIFF成功");
                return true;
            }
            catch (Exception ex)
            {
                throw new Exception($"写入TIFF文件时出错: {ex.Message}");
            }
        }

        /// <summary>
        /// 创建默认的PSIA头部
        /// </summary>
        /// <returns></returns>
        private static PSIAHeader CreateDefaultPSIAHeader()
        {
            PSIAHeader header = new PSIAHeader
            {
                ImageType = 0,
                SourceName = new byte[64],
                ImageMode = new byte[16],
                LpfStrength = 0,
                AutoFlatten = 0,
                AcTrack = 0,
                Xres = 512,
                Yres = 256,
                Angle = 0,
                SineScan = 0,
                OverscanRate = 0.1,
                Forward = 1,
                ScanUp = 1,
                SwapXY = 0,
                XReal = 2.500,
                YReal = 2.500,
                XOffset = -2.6015,
                YOffset = 2.6179,
                ScanRate = 1,
                SetPoint = 0.0062,
                SetPointUnit = new byte[16],
                TipBias = 0,
                SampleBias = 0,
                DataGain = 1.0,
                ZScale = 1,
                ZOffset = 0,
                ZUnit = new byte[16],
                DataMin = 0xFB088411,
                DataMax = 0xFA626580,
                DataAvg = 0,
                Compression = 0,
                Logscale = 0,
                Square = 0,
                ZServoGain = 1.5,
                ZScannerRange = 1,
                XYVoltageMode = new byte[16],
                ZVoltageMode = new byte[16],
                XYServoMode = new byte[16],
                DataType = 2,
                Reserved1 = 0,
                Reserved2 = 0,
                NcmAmplitude = 0.0068,
                NcmFrequency = 3.2403e+05,
                HeadRotateAngle = 0,
                CantileverName = new byte[32],
                Tail = new byte[164]
            };

            GenerateUint8Array(header.SourceName, "Height");
            GenerateUint8Array(header.ImageMode, "NC-AFM");
            GenerateUint8Array(header.SetPointUnit, "um");
            GenerateUint8Array(header.ZUnit, "um");
            GenerateUint8Array(header.XYVoltageMode, "LARGE");
            GenerateUint8Array(header.ZVoltageMode, "LARGE");
            GenerateUint8Array(header.XYServoMode, "On");
            GenerateUint8Array(header.CantileverName, "OMCL-AC160TS");

            // 尾部数据
            byte[] tailData = new byte[] { 42, 191, 255, 45, 197, 234, 44, 64, 0, 0, 0, 196, 175, 151, 7, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 240, 63, 0, 0, 0, 0, 0, 0, 240, 63, 0, 0, 0, 0, 164, 112, 61, 189, 239, 221, 147, 193, 92, 143, 194, 2, 106, 118, 150, 193, 132, 90, 75, 202, 135, 72, 193, 64, 155, 52, 120, 30, 212, 100, 168, 64, 143, 48, 194, 227, 225, 175, 192, 64, 22, 234, 120, 142, 229, 3, 176, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
            Array.Copy(tailData, header.Tail, Math.Min(tailData.Length, 164));

            return header;
        }

        /// <summary>
        /// 生成uint8数组(特殊格式，16进制字符，每个字母中间使用0填充)
        /// </summary>
        /// <param name="uint8Array"></param>
        /// <param name="data"></param>
        /// <returns></returns>
        private static bool GenerateUint8Array(byte[] uint8Array, string data)
        {
            Array.Clear(uint8Array, 0, uint8Array.Length);
            int length = data.Length;
            if (length * 2 > uint8Array.Length)
            {
                return false;
            }

            for (int i = 0; i < length; i++)
            {
                uint8Array[2 * i] = (byte)data[i];
            }
            return true;
        }

        /// <summary>
        /// TIFF信息转PSIA头部信息
        /// </summary>
        /// <param name="info"></param>
        /// <param name="header"></param>
        /// <returns></returns>
        private static bool TiffInfoToPSIAHeader(TIFFINFO info, ref PSIAHeader header)
        {
            header.Xres = (uint)info.XOriginRes;
            header.Yres = (uint)info.YOriginRes;
            header.XReal = info.XReal;
            header.YReal = info.YReal;
            GenerateUint8Array(header.SetPointUnit, info.XyUnit);
            GenerateUint8Array(header.ZUnit, info.ZUnit);
            header.Angle = info.Angle;
            return true;
        }

        /// <summary>
        /// TIFF信息转CustomData
        /// </summary>
        /// <param name="info"></param>
        /// <param name="customData"></param>
        /// <returns></returns>
        private static bool TiffInfoToCustomData(TIFFINFO info, ref TiffCustomData customData)
        {
            customData.ROI_x1 = info.ROI_x1;
            customData.ROI_y1 = info.ROI_y1;
            customData.ROI_x2 = info.ROI_x2;
            customData.ROI_y2 = info.ROI_y2;
            return true;
        }

        /// <summary>
        /// 结构体转字节数组
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="structure"></param>
        /// <returns></returns>
        private static byte[] StructureToByteArray<T>(T structure) where T : struct
        {
            int size = System.Runtime.InteropServices.Marshal.SizeOf(structure);
            byte[] bytes = new byte[size];
            IntPtr ptr = System.Runtime.InteropServices.Marshal.AllocHGlobal(size);
            try
            {
                System.Runtime.InteropServices.Marshal.StructureToPtr(structure, ptr, false);
                System.Runtime.InteropServices.Marshal.Copy(ptr, bytes, 0, size);
            }
            finally
            {
                System.Runtime.InteropServices.Marshal.FreeHGlobal(ptr);
            }
            return bytes;
        }

        #endregion
    }
}
